using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;

namespace Christian.Helle.PocketNews.PocketPC.Controls
{
	/// <summary>
	/// Fill a control with gradient color
	/// </summary>
	public sealed class Gradient
	{
		private struct TRIVERTEX
		{
			private int x;
			private int y;
			private ushort Red;
			private ushort Green;
			private ushort Blue;
			private ushort Alpha;

			public TRIVERTEX(int x, int y, Color color)
				: this(x, y, color.R, color.G, color.B, color.A)
			{
			}

			public TRIVERTEX(
				int x, int y,
				ushort red, ushort green, ushort blue,
				ushort alpha)
			{
				this.x = x;
				this.y = y;
				Red = (ushort)(red << 8);
				Green = (ushort)(green << 8);
				Blue = (ushort)(blue << 8);
				Alpha = (ushort)(alpha << 8);
			}
		}

		private struct GRADIENT_RECT
		{
			private uint UpperLeft;
			private uint LowerRight;

			public GRADIENT_RECT(uint ul, uint lr)
			{
				UpperLeft = ul;
				LowerRight = lr;
			}
		}

		[DllImport("coredll.dll", SetLastError = true, EntryPoint = "GradientFill")]
		private static extern bool GradientFill(
			IntPtr hdc,
			TRIVERTEX[] pVertex,
			uint dwNumVertex,
			GRADIENT_RECT[] pMesh,
			uint dwNumMesh,
			uint dwMode);

		private const int GRADIENT_FILL_RECT_H = 0x00000000;
		private const int GRADIENT_FILL_RECT_V = 0x00000001;

		/// <summary>
		/// This method wraps the P/Invoke to GradientFill.
		/// </summary>
		/// <param name="gr">The Graphics object we are filling</param>
		/// <param name="rc">The rectangle to fill</param>
		/// <param name="startColor">The starting color for the fill</param>
		/// <param name="endColor">The ending color for the fill</param>
		/// <param name="fillDir">The direction to fill</param>
		/// <returns>Returns true if the call to GradientFill succeeded; false otherwise.</returns>
		public static bool Fill(
			Graphics gr,
			Rectangle rc,
			Color startColor, Color endColor,
			FillDirection fillDir)
		{
			bool b;

			// Initialize the data to be used in the call to GradientFill.
			TRIVERTEX[] tva = new TRIVERTEX[2];
			tva[0] = new TRIVERTEX(rc.X, rc.Y, endColor);
			tva[1] = new TRIVERTEX(rc.Right, rc.Bottom, startColor);
			GRADIENT_RECT[] gra = new GRADIENT_RECT[] { new GRADIENT_RECT(0, 1) };

			// Get the hDC from the Graphics object.
			IntPtr hdc = gr.GetHdc();

			try {
				// P/Invoke to GradientFill.
				b = GradientFill(
					hdc,
					tva,
					(uint)tva.Length,
					gra,
					(uint)gra.Length,
					(uint)fillDir);

				Debug.Assert(b, string.Format("GradientFill failed: {0}",
																			Marshal.GetLastWin32Error()));
			}
			catch (MissingMethodException) {
				b = false;
				Debug.Assert(b, "GradientFill failed:  Not supported in this version of Windows Mobile");
			}

			// Release the hDC from the Graphics object.
			gr.ReleaseHdc(hdc);

			return b;
		}

		/// <summary>
		/// The direction to the GradientFill will follow
		/// </summary>
		public enum FillDirection
		{
			/// <summary>
			/// The fill goes horizontally
			/// </summary>
			RightToLeft = GRADIENT_FILL_RECT_H,
			/// <summary>
			/// The fill goes vertically
			/// </summary>
			TopToBottom = GRADIENT_FILL_RECT_V
		}
	}
}
